/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

//! Generate file sizes used by synthetic repos.
//!
//! Practically, log2(file size) follows a normal distribution.
//!
//! See also "A Large-Scale Study of File-System Contents"
//! (https://www.microsoft.com/en-us/research/wp-content/uploads/1999/01/Sigmetrics1999.pdf)

/// Given a random value `x`, produce a "realistic" file size.
///
/// Under the hood, turn universal distribution into (roughly) log-normal
/// distribution.
pub(crate) fn generate_file_size(x: u64) -> u64 {
    // Use lookup tables to avoid (complex / slow) floating point calculations.
    // First look at the highest byte of `x`, if it's 0xff, then check the next bytes,
    // to make it possible to return large sizes.
    const SIZES_TABLE: [[u32; 256]; 5] = [
        // [[[cog
        // import cog
        // from scipy.stats import norm
        // # mu, std calculated via norm.fit with a small subset of fbsource file sizes.
        // mu = 11.49
        // std = 2.44
        // N = 256
        //
        // def calculate_sizes(byte_index):
        //      start = 1 - (1 / (N ** byte_index))
        //      step = 1 / (N ** (byte_index + 1))
        //      return [2 ** norm.ppf(start + (i * step), loc=mu, scale=std) for i in range(N)]
        //
        // for i in range(5):
        //      sizes = calculate_sizes(i)
        //      sizes_str = ', '.join(map(lambda x: str(int(x)), sizes))
        //      cog.outl(f"[{sizes_str}],")
        // ]]]
        [
            0, 31, 48, 62, 75, 87, 99, 111, 123, 134, 146, 157, 168, 180, 191, 203, 214, 226, 237,
            249, 261, 273, 285, 297, 309, 321, 334, 346, 359, 372, 384, 397, 411, 424, 437, 451,
            464, 478, 492, 506, 521, 535, 550, 565, 579, 595, 610, 625, 641, 657, 673, 689, 706,
            722, 739, 756, 773, 791, 808, 826, 844, 862, 881, 900, 919, 938, 957, 977, 997, 1017,
            1038, 1059, 1080, 1101, 1122, 1144, 1166, 1189, 1212, 1235, 1258, 1282, 1306, 1330,
            1354, 1379, 1405, 1430, 1456, 1483, 1509, 1536, 1564, 1592, 1620, 1648, 1677, 1707,
            1737, 1767, 1798, 1829, 1861, 1893, 1925, 1958, 1992, 2026, 2060, 2095, 2131, 2167,
            2204, 2241, 2279, 2317, 2356, 2396, 2436, 2477, 2519, 2561, 2604, 2647, 2691, 2736,
            2782, 2829, 2876, 2924, 2973, 3022, 3073, 3124, 3176, 3230, 3284, 3339, 3395, 3452,
            3510, 3569, 3629, 3690, 3753, 3816, 3881, 3947, 4014, 4082, 4152, 4223, 4295, 4369,
            4445, 4522, 4600, 4680, 4762, 4845, 4930, 5017, 5105, 5196, 5288, 5383, 5479, 5578,
            5679, 5782, 5887, 5995, 6106, 6219, 6334, 6453, 6574, 6698, 6825, 6956, 7089, 7226,
            7367, 7511, 7659, 7811, 7967, 8128, 8293, 8462, 8636, 8815, 9000, 9190, 9385, 9587,
            9794, 10009, 10230, 10458, 10693, 10937, 11188, 11448, 11718, 11996, 12285, 12585,
            12896, 13218, 13553, 13902, 14264, 14641, 15035, 15445, 15873, 16321, 16789, 17280,
            17794, 18334, 18901, 19498, 20127, 20790, 21492, 22235, 23024, 23861, 24754, 25706,
            26725, 27819, 28995, 30264, 31639, 33132, 34762, 36549, 38518, 40699, 43131, 45863,
            48959, 52500, 56598, 61407, 67148, 74146, 82913, 94302, 109871, 132864, 171618, 258636,
        ],
        [
            258636, 259213, 259793, 260377, 260964, 261555, 262149, 262747, 263348, 263952, 264561,
            265173, 265788, 266407, 267031, 267657, 268288, 268922, 269561, 270203, 270849, 271500,
            272154, 272812, 273475, 274142, 274813, 275488, 276168, 276852, 277540, 278233, 278930,
            279632, 280339, 281050, 281766, 282487, 283212, 283943, 284678, 285418, 286163, 286914,
            287669, 288430, 289196, 289968, 290745, 291527, 292315, 293108, 293907, 294712, 295523,
            296339, 297161, 297990, 298824, 299665, 300512, 301365, 302224, 303091, 303963, 304842,
            305728, 306621, 307521, 308427, 309341, 310262, 311190, 312126, 313069, 314019, 314977,
            315943, 316917, 317899, 318889, 319887, 320893, 321908, 322931, 323963, 325004, 326054,
            327113, 328181, 329258, 330345, 331441, 332547, 333663, 334789, 335925, 337072, 338228,
            339396, 340574, 341764, 342964, 344176, 345400, 346635, 347882, 349141, 350412, 351696,
            352992, 354302, 355624, 356960, 358309, 359673, 361050, 362441, 363847, 365268, 366704,
            368155, 369622, 371104, 372603, 374118, 375650, 377200, 378766, 380350, 381952, 383573,
            385213, 386871, 388549, 390247, 391966, 393705, 395465, 397247, 399051, 400877, 402726,
            404599, 406496, 408417, 410363, 412335, 414333, 416358, 418410, 420490, 422598, 424736,
            426904, 429102, 431332, 433594, 435889, 438218, 440581, 442980, 445416, 447888, 450399,
            452950, 455541, 458173, 460848, 463566, 466330, 469140, 471997, 474904, 477861, 480870,
            483932, 487049, 490223, 493456, 496749, 500104, 503524, 507010, 510564, 514190, 517889,
            521664, 525517, 529452, 533471, 537578, 541775, 546067, 550456, 554947, 559543, 564250,
            569070, 574010, 579074, 584268, 589598, 595068, 600687, 606461, 612396, 618502, 624787,
            631259, 637928, 644805, 651901, 659227, 666798, 674627, 682729, 691122, 699822, 708850,
            718228, 727979, 738129, 748706, 759742, 771273, 783336, 795976, 809240, 823184, 837868,
            853362, 869746, 887111, 905560, 925215, 946217, 968731, 992954, 1019120, 1047511,
            1078471, 1112427, 1149911, 1191601, 1238378, 1291408, 1352278, 1423216, 1507473,
            1610029, 1739015, 1908901, 2148897, 2531226, 3322295,
        ],
        [
            3322295, 3327311, 3332353, 3337422, 3342517, 3347640, 3352790, 3357967, 3363172,
            3368406, 3373667, 3378958, 3384277, 3389626, 3395003, 3400411, 3405849, 3411317,
            3416816, 3422345, 3427906, 3433498, 3439123, 3444779, 3450468, 3456190, 3461944,
            3467733, 3473555, 3479411, 3485302, 3491228, 3497189, 3503185, 3509218, 3515287,
            3521392, 3527535, 3533715, 3539933, 3546190, 3552485, 3558820, 3565194, 3571608,
            3578062, 3584558, 3591094, 3597673, 3604294, 3610957, 3617664, 3624415, 3631210,
            3638049, 3644934, 3651865, 3658842, 3665866, 3672937, 3680056, 3687224, 3694441,
            3701708, 3709024, 3716392, 3723812, 3731283, 3738808, 3746386, 3754018, 3761705,
            3769447, 3777246, 3785101, 3793014, 3800986, 3809017, 3817108, 3825259, 3833472,
            3841747, 3850085, 3858488, 3866955, 3875488, 3884088, 3892755, 3901491, 3910296,
            3919171, 3928118, 3937137, 3946230, 3955397, 3964640, 3973959, 3983356, 3992832,
            4002388, 4012025, 4021745, 4031548, 4041436, 4051411, 4061473, 4071624, 4081865,
            4092198, 4102624, 4113145, 4123762, 4134477, 4145291, 4156205, 4167223, 4178344,
            4189572, 4200907, 4212351, 4223907, 4235577, 4247362, 4259264, 4271285, 4283428,
            4295694, 4308086, 4320606, 4333257, 4346040, 4358959, 4372015, 4385212, 4398552,
            4412037, 4425671, 4439457, 4453396, 4467494, 4481752, 4496173, 4510762, 4525521,
            4540455, 4555565, 4570858, 4586335, 4602002, 4617862, 4633920, 4650179, 4666644,
            4683321, 4700213, 4717325, 4734664, 4752233, 4770038, 4788086, 4806381, 4824931,
            4843740, 4862815, 4882164, 4901793, 4921709, 4941919, 4962432, 4983256, 5004398,
            5025867, 5047673, 5069824, 5092330, 5115202, 5138450, 5162085, 5186118, 5210561,
            5235427, 5260728, 5286478, 5312691, 5339383, 5366568, 5394262, 5422484, 5451249,
            5480578, 5510490, 5541005, 5572144, 5603932, 5636391, 5669547, 5703427, 5738059,
            5773472, 5809698, 5846770, 5884724, 5923596, 5963428, 6004260, 6046138, 6089110,
            6133227, 6178543, 6225117, 6273011, 6322293, 6373035, 6425314, 6479213, 6534824,
            6592244, 6651579, 6712944, 6776463, 6842274, 6910526, 6981382, 7055023, 7131645,
            7211469, 7294737, 7381719, 7472716, 7568065, 7668148, 7773393, 7884287, 8001388,
            8125332, 8256857, 8396818, 8546218, 8706237, 8878280, 9064038, 9265560, 9485367,
            9726603, 9993248, 10290438, 10624940, 11005907, 11446099, 11963993, 12587660, 13362482,
            14368345, 15764359, 17937190, 22277406,
        ],
        [
            22277406, 22304370, 22331469, 22358704, 22386077, 22413589, 22441242, 22469036,
            22496973, 22525054, 22553280, 22581654, 22610175, 22638846, 22667669, 22696643,
            22725771, 22755055, 22784496, 22814094, 22843853, 22873773, 22903855, 22934103,
            22964516, 22995097, 23025847, 23056769, 23087863, 23119132, 23150577, 23182199,
            23214002, 23245986, 23278154, 23310507, 23343048, 23375778, 23408698, 23441812,
            23475121, 23508628, 23542334, 23576241, 23610352, 23644668, 23679193, 23713928,
            23748875, 23784038, 23819417, 23855017, 23890838, 23926884, 23963157, 23999659,
            24036394, 24073364, 24110571, 24148019, 24185710, 24223646, 24261832, 24300269,
            24338960, 24377910, 24417120, 24456594, 24496335, 24536346, 24576631, 24617193,
            24658035, 24699161, 24740574, 24782278, 24824277, 24866574, 24909173, 24952078,
            24995293, 25038822, 25082669, 25126838, 25171333, 25216159, 25261320, 25306820,
            25352665, 25398859, 25445406, 25492312, 25539580, 25587218, 25635229, 25683618,
            25732392, 25781555, 25831114, 25881073, 25931440, 25982218, 26033416, 26085038,
            26137092, 26189583, 26242518, 26295905, 26349749, 26404058, 26458839, 26514100,
            26569848, 26626090, 26682836, 26740091, 26797866, 26856168, 26915006, 26974388,
            27034325, 27094824, 27155897, 27217551, 27279798, 27342648, 27406110, 27470196,
            27534917, 27600284, 27666308, 27733002, 27800378, 27868448, 27937225, 28006722,
            28076953, 28147932, 28219673, 28292190, 28365499, 28439616, 28514556, 28590336,
            28666973, 28744484, 28822887, 28902201, 28982444, 29063637, 29145799, 29228951,
            29313115, 29398313, 29484567, 29571902, 29660342, 29749912, 29840637, 29932545,
            30025664, 30120023, 30215650, 30312577, 30410835, 30510459, 30611481, 30713937,
            30817864, 30923300, 31030285, 31138860, 31249066, 31360949, 31474555, 31589932,
            31707128, 31826197, 31947192, 32070170, 32195189, 32322310, 32451599, 32583120,
            32716944, 32853145, 32991798, 33132983, 33276785, 33423290, 33572592, 33724786,
            33879975, 34038265, 34199769, 34364604, 34532897, 34704777, 34880385, 35059868,
            35243380, 35431085, 35623159, 35819787, 36021164, 36227499, 36439016, 36655951,
            36878557, 37107105, 37341883, 37583204, 37831398, 38086824, 38349869, 38620947,
            38900507, 39189038, 39487065, 39795163, 40113957, 40444129, 40786428, 41141672,
            41510765, 41894702, 42294586, 42711643, 43147239, 43602900, 44080344, 44581506,
            45108583, 45664073, 46250842, 46872189, 47531942, 48234568, 48985330, 49790471,
            50657479, 51595422, 52615423, 53731309, 54960542, 56325578, 57855919, 59591305,
            61586933, 63922383, 66717944, 70167011, 74607777, 80708484, 90076369, 108403397,
        ],
        [
            108403397, 108515863, 108628878, 108742446, 108856572, 108971262, 109086520, 109202352,
            109318762, 109435756, 109553339, 109671517, 109790295, 109909679, 110029673, 110150284,
            110271518, 110393380, 110515877, 110639013, 110762796, 110887231, 111012325, 111138083,
            111264513, 111391621, 111519413, 111647896, 111777077, 111906963, 112037560, 112168876,
            112300918, 112433693, 112567209, 112701472, 112836491, 112972274, 113108827, 113246160,
            113384279, 113523194, 113662912, 113803443, 113944794, 114086974, 114229991, 114373856,
            114518577, 114664164, 114810624, 114957969, 115106208, 115255351, 115405407, 115556387,
            115708301, 115861159, 116014973, 116169753, 116325509, 116482254, 116639999, 116798754,
            116958533, 117119346, 117281206, 117444126, 117608117, 117773193, 117939367, 118106652,
            118275061, 118444608, 118615307, 118787172, 118960218, 119134460, 119309912, 119486589,
            119664508, 119843683, 120024132, 120205870, 120388914, 120573281, 120758990, 120946056,
            121134499, 121324336, 121515587, 121708270, 121902405, 122098012, 122295111, 122493723,
            122693869, 122895570, 123098848, 123303726, 123510227, 123718373, 123928189, 124139699,
            124352928, 124567901, 124784644, 125003184, 125223548, 125445762, 125669857, 125895859,
            126123800, 126353709, 126585616, 126819555, 127055556, 127293653, 127533880, 127776272,
            128020863, 128267691, 128516792, 128768204, 129021967, 129278120, 129536705, 129797763,
            130061337, 130327471, 130596212, 130867604, 131141696, 131418537, 131698177, 131980666,
            132266059, 132554410, 132845773, 133140207, 133437771, 133738524, 134042530, 134349852,
            134660556, 134974711, 135292385, 135613650, 135938582, 136267255, 136599749, 136936144,
            137276523, 137620974, 137969584, 138322445, 138679652, 139041302, 139407496, 139778339,
            140153937, 140534403, 140919850, 141310400, 141706174, 142107300, 142513910, 142926142,
            143344137, 143768043, 144198012, 144634202, 145076779, 145525913, 145981781, 146444569,
            146914468, 147391678, 147876407, 148368873, 148869301, 149377927, 149894996, 150420766,
            150955504, 151499491, 152053020, 152616398, 153189945, 153773999, 154368913, 154975057,
            155592819, 156222610, 156864858, 157520017, 158188563, 158870999, 159567856, 160279693,
            161007104, 161750715, 162511190, 163289234, 164085594, 164901066, 165736494, 166592780,
            167470884, 168371834, 169296726, 170246736, 171223126, 172227251, 173260570, 174324653,
            175421200, 176552046, 177719183, 178924774, 180171173, 181460949, 182796914, 184182149,
            185620042, 187114333, 188669154, 190289093, 191979260, 193745367, 195593821, 197531846,
            199567623, 201710456, 203970995, 206361493, 208896141, 211591493, 214467006, 217545745,
            220855317, 224429113, 228308013, 232542747, 237197257, 242353604, 248119347, 254639036,
            262112888, 270828718, 281220137, 293981616, 310322164, 332617721, 366542517, 431979804,
        ],
        // [[[end]]]
    ];
    let x_bytes = x.to_be_bytes();
    for i in 0..SIZES_TABLE.len() {
        if x_bytes[i] != 0xff {
            let current_size = SIZES_TABLE[i][x_bytes[i] as usize] as u64;
            let next_size = SIZES_TABLE[i][(x_bytes[i] + 1) as usize] as u64;
            let scale = ((x & (u64::MAX >> (i + 1))) << (i + 1)) >> 32;
            let size = current_size + ((next_size - current_size).saturating_mul(scale) >> 32);
            return size;
        }
    }
    // Well, this seems to be a really large file. But we don't want unlimited size.
    // Cap the maximum size to be 2x of max(SIZES_TABLE).
    let size = SIZES_TABLE[SIZES_TABLE.len() - 1][255] as u64;
    size.saturating_add(size & x)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_gen_file_size_spot_check() {
        assert_eq!(generate_file_size(0), 0);
        assert_eq!(generate_file_size(10), 0);
        assert_eq!(generate_file_size(1 << 31), 0);
        assert_eq!(generate_file_size(1 << 62), 928);
        assert_eq!(generate_file_size(1 << 63), 2876);
        assert_eq!(generate_file_size(0xff010000_00000000), 259783);
        assert_eq!(generate_file_size(0xff01c000_00000000), 259783);
        assert_eq!(generate_file_size(0xff01ffff_00000000), 259784);
        assert_eq!(generate_file_size(0xff020000_00000000), 260367);
        assert_eq!(generate_file_size(0xff020000_00000000), 260367);
        assert_eq!(generate_file_size(0xffff0300_00000000), 3342516);
        assert_eq!(generate_file_size(0xffffffff_00000000), 108515862);
        assert_eq!(generate_file_size(0xffffffff_12345678), 110639012);
        assert_eq!(generate_file_size(0xffffffff_fe000000), 431979803);
        assert_eq!(generate_file_size(0xffffffff_ffc00000), 859798812);
        assert_eq!(generate_file_size(u64::MAX), 863959608);
    }
}
